#include "widget.h"

#define TIMEOUT 100

float vertices[] = {
    // positions
    -0.5f, -0.5f, -0.5f,
    0.5f, -0.5f, -0.5f,
    0.5f,  0.5f, -0.5f,
    0.5f,  0.5f, -0.5f,
    -0.5f,  0.5f, -0.5f,
    -0.5f, -0.5f, -0.5f,

    -0.5f, -0.5f,  0.5f,
    0.5f, -0.5f,  0.5f,
    0.5f,  0.5f,  0.5f,
    0.5f,  0.5f,  0.5f,
    -0.5f,  0.5f,  0.5f,
    -0.5f, -0.5f,  0.5f,

    -0.5f,  0.5f,  0.5f,
    -0.5f,  0.5f, -0.5f,
    -0.5f, -0.5f, -0.5f,
    -0.5f, -0.5f, -0.5f,
    -0.5f, -0.5f,  0.5f,
    -0.5f,  0.5f,  0.5f,

    0.5f,  0.5f,  0.5f,
    0.5f,  0.5f, -0.5f,
    0.5f, -0.5f, -0.5f,
    0.5f, -0.5f, -0.5f,
    0.5f, -0.5f,  0.5f,
    0.5f,  0.5f,  0.5f,

    -0.5f, -0.5f, -0.5f,
    0.5f, -0.5f, -0.5f,
    0.5f, -0.5f,  0.5f,
    0.5f, -0.5f,  0.5f,
    -0.5f, -0.5f,  0.5f,
    -0.5f, -0.5f, -0.5f,

    -0.5f,  0.5f, -0.5f,
    0.5f,  0.5f, -0.5f,
    0.5f,  0.5f,  0.5f,
    0.5f,  0.5f,  0.5f,
    -0.5f,  0.5f,  0.5f,
    -0.5f,  0.5f, -0.5f,
};

const float PI = 3.1415926;
QVector3D lightPos(1.2f, 1.0f, 2.0f);
QVector3D lightColor(1.0f, 1.0f, 1.0f);

MyGLWidget::MyGLWidget(QWidget *parent) : QOpenGLWidget(parent)
{
    m_camera.Position = QVector3D(0.0,0.0,10.0);

    m_timer = new QTimer(this);
    connect(m_timer,&QTimer::timeout,this,[&]
    {
        update();
    });
    m_timer->start(TIMEOUT);
    m_time.start();
}

MyGLWidget::~MyGLWidget()
{
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
}

void MyGLWidget::initializeGL()
{
    initializeOpenGLFunctions(); // 初始化 OpenGL 函数

    shader.install(":/shader/shader.vert", ":/shader/shader.frag");

    //创建、绑定纹理
    //texture1 = loadTexture(":/img/container2.png", true);
    //texture2 = loadTexture(":/img/container2_specular.png");

    QOpenGLContext* context = QOpenGLContext::currentContext();
    if (!context)
    {
        qWarning() << "No current OpenGL context";
        return ;
    }

    QOpenGLFunctions_3_3_Core* funcs = context->versionFunctions<QOpenGLFunctions_3_3_Core>();
    if (!funcs)
    {
        qWarning() << "Could not obtain required OpenGL context version";
        return ;
    }
    m_model = new Model(funcs, ":/img/zhiche.glb");

#if 0
    QVector<QVector3D> s_vertices;
    for (size_t i = 0; i < sizeof(vertices) / sizeof(float); i += 3)
    {
        QVector3D vertex(vertices[i], vertices[i + 1], vertices[i + 2]);
        s_vertices.append(vertex);
    }
    QVector<unsigned int> _indices;
    for(int i=0;i<36;i++)
    {
        _indices.push_back(i);
    }
    mesh = new Mesh(funcs, s_vertices,_indices, QVector<QVector3D>{}, QVector<QVector2D>{}, Material{});
#else
    vector<Vertex> _vertices(36);
    vector<unsigned int> _indices;
    memcpy(&_vertices[0],vertices,sizeof(vertices));
    for(int i=0;i<36;i++)
    {
        _indices.push_back(i);
    }
    //mesh = new Mesh(funcs, _vertices,_indices,vector<Texture>{});
#endif


}

void MyGLWidget::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除颜色缓冲区

    float time = m_time.elapsed()/50.0;

    QMatrix4x4 model, view, projection;
    projection.setToIdentity();
    projection.perspective(m_camera.Zoom, (float)width() / (float)height(), 0.1f, 100.0f);

    view = m_camera.GetViewMatrix();

    shader.use();
    shader.setUniformValue("viewPos",m_camera.Position);
    shader.setUniformValue("projection", projection);
    shader.setUniformValue("view", view);
    model.setToIdentity();
    //model.fill(0.0);
    model.rotate(time, 0.0f, 1.0f, 0.0f);
    shader.setUniformValue("model", model);

    //shader.setUniformValue("light.position", m_camera.Position);

    shader.setUniformValue("light.ambient", 0.4f, 0.4f, 0.4f);
    shader.setUniformValue("light.diffuse", 0.9f, 0.9f, 0.9f);
    shader.setUniformValue("light.specular", 1.0f, 1.0f, 1.0f);

    //shader.setUniformValue("material.shininess", 32.0f);
    shader.setUniformValue("light.direction", -0.2f, -1.0f, -0.3f);

    m_model->Draw(shader);
    //mesh->Draw(shader);
}

void MyGLWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h); // 设置视口大小
}








unsigned int MyGLWidget::loadTexture(const char *fileName, bool alpha)
{
    unsigned int texture;
    glGenTextures(1, &texture); // 生成纹理 ID
    glBindTexture(GL_TEXTURE_2D, texture); // 绑定纹理

    // 设置纹理参数
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#if 1
    // 加载图片并转换为 OpenGL 格式
    QImage image;
    if (!image.load(fileName))
    {
        qWarning() << "Failed to load texture image";
        return 0;
    }
    image = QGLWidget::convertToGLFormat(image); // 转换为 OpenGL 格式
    unsigned char *data = image.bits();
    // 生成纹理
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    glGenerateMipmap(GL_TEXTURE_2D); // 生成多级渐远纹理
#else

    QFile file(fileName);
    file.copy(file.fileName(), QFileInfo(file).fileName());

    int width, height, nrChannels;
    stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
    unsigned char *data = stbi_load(QFileInfo(file).fileName().toStdString().c_str(), &width, &height, &nrChannels, 0);
    if (data)//awesomeface  container
    {
        if(alpha)
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
        else
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    }
    else
    {
        std::cout << "Failed to load texture1" << std::endl;
    }
    stbi_image_free(data);
#endif
    return texture;
}

void MyGLWidget::keyPressEvent(QKeyEvent *event)
{
#if 01
    float deltatime=TIMEOUT / 1000.0;
    switch(event->key())
    {
    case Qt::Key_Up:ratio += 0.1;break;
    case Qt::Key_Down:ratio -= 0.1;break;
    case Qt::Key_W: m_camera.ProcessKeyboard(FORWARD,deltatime);break;
    case Qt::Key_S: m_camera.ProcessKeyboard(BACKWARD,deltatime);break;
    case Qt::Key_D: m_camera.ProcessKeyboard(RIGHT,deltatime);break;
    case Qt::Key_A: m_camera.ProcessKeyboard(LEFT,deltatime);break;
    }

    if(ratio > 1) ratio = 1;
    if(ratio < 0) ratio = 0;

    makeCurrent();
    shader.bind();
    shader.setUniformValue("ratio",ratio);
    update();
    doneCurrent();
#endif
}

void MyGLWidget::mouseMoveEvent(QMouseEvent *event)
{
#if 01
    //qDebug() << "mouseMoveEvent";
    static QPoint lastPos(width()/2,height()/2);
    auto currentPos=event->pos();
    deltaPos=currentPos-lastPos;
    lastPos=currentPos;

    m_camera.ProcessMouseMovement(deltaPos.x(),-deltaPos.y());
    update();
#endif
}

void MyGLWidget::wheelEvent(QWheelEvent *event)
{
    //qDebug() << "wheelEvent";
    m_camera.ProcessMouseScroll(event->angleDelta().y()/120);
    update();
}
